package nl.sweet.testsweet;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Calendar;
import java.util.LinkedList;

import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.textui.TestRunner;

/**
 * The test application which runs over the test classes given by the test suite.
 * @author wessels
 */
public class TestSweet
{
	/** The version of the application. */
	public static final String APPLICATON_VERSION = "1.0.0";

	/**
	 * Constructor.
	 * @param classes The LinkedList with the testcases to perform.
	 * @param testListener The listener for the testcases.
	 */
	public TestSweet(LinkedList<Class< ? extends TestSweetTestCase>> classes,
			TestSweetListener testListener)
	{
		// Tell the listener how much classes there are.
		testListener.setAmountOfTests(classes.size());

		double totalTime = 0;
		for (int i = 0; i < classes.size(); ++i)
		{

			// Get the unit test class to run.
			Class< ? extends TestSweetTestCase> testClass = classes.get(i);

			// Tel the listener which test this is.
			testListener.setCurrentTest(i + 1, testClass);

			// Create a test suite with the current test class.
			TestSuite test = new TestSuite(testClass);

			// Point the std-out and std-error to a print stream.
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
			PrintStream stdOutput = System.out;
			PrintStream stdError = System.err;
			System.setOut(new PrintStream(outputStream));
			System.setErr(new PrintStream(errorStream));
			
			// Run the test.
			long timeBefore = Calendar.getInstance().getTimeInMillis();
			TestResult results = TestRunner.run(test);
			double timeTaken = ((double) (Calendar.getInstance().getTimeInMillis() - timeBefore) / 1000);
			
			// Set the std-out and std-error back to normal.
			try
			{
				outputStream.close();
				errorStream.close();
			}
			catch (IOException e)
			{
				e.printStackTrace();
			}
			System.setOut(stdOutput);
			System.setErr(stdError);

			// Create a new results object of the current test.
			testListener.addTestSuiteResult(new TestSweetResult(testClass, errorStream.toString(),
					outputStream.toString(), timeTaken, results));
			
			

			// Keep track of the total time taken.
			totalTime += timeTaken;
		}

		// Tell the listener how much time it took the suite to test it all.
		testListener.setTotalTime(totalTime);
	}
}
